using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Diagnostics;

namespace BurningSphere.Simulator.Code
{
	/// <summary>
	/// Script
	/// </summary>
	public class Script
	{
		string code;
		string template;
		string name;
		List<string> includes = new List<string>();
		Assembly assembly;

		/// <summary>
		/// Ctor
		/// </summary>
		public Script(string template,string name)
		{
			includes.Add("System.dll");
			includes.Add("System.Data.dll");
			includes.Add("System.Xml.dll");

			this.template = template;
			this.name = name;
		}

		/// <summary>
		/// Includes
		/// Files of assemblies to include
		/// </summary>
		public List<string> Include
		{
			get
			{
				return includes;
			}
		}

		/// <summary>
		/// Code
		/// </summary>
		public string Code
		{
			get
			{
				return template.Replace("[ClassName]",name).Replace("[Code]",code);
			}
			set
			{
				code = value;
				assembly = null;
			}
		}

		/// <summary>
		/// Assembly
		/// </summary>
		public Assembly Assembly
		{
			get
			{
				if (assembly == null)
				{
					assembly = Compile();
				}
				return assembly;
			}
		}

		/// <summary>
		/// Compile
		/// </summary>
		private Assembly Compile()
		{
			ICodeCompiler compiler = new CSharpCodeProvider().CreateCompiler();

			CompilerParameters parameters = new CompilerParameters();
			foreach (string include in includes)
			{
				parameters.ReferencedAssemblies.Add(include);
			}
			parameters.GenerateInMemory = false;

			CompilerResults compiled = compiler.CompileAssemblyFromSource(parameters, Code);
			if (compiled.Errors.HasErrors)
			{
				StringBuilder builder = new StringBuilder();
				builder.AppendLine(compiled.Errors.Count.ToString() + " Script errors:");
				for (int x = 0; x < compiled.Errors.Count; x++)
				{
					builder.AppendLine("\r\nLine: ");
					builder.AppendLine(compiled.Errors[x].Line.ToString() + " - " + compiled.Errors[x].ErrorText);
				}
				builder.AppendLine("Compilation Failed");
				throw new Exception(builder.ToString());
			}

			return compiled.CompiledAssembly;
		}
	}
}
